<template>
  <div>
    <!-- 面包屑导航区 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>用户管理</el-breadcrumb-item>
      <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片视图区域 卡片就是容器-->
    <el-card class="box-card">
      <!-- row表格化区域  col的span代表元素所占的格子数  gutter间隔-->
      <el-row :gutter="20">
        <el-col :span="9">
          <el-input
            placeholder="请输入内容"
            v-model="queryInfo.query"
            clearable
            @clear="getUserList"
          >
            <!-- slot表示要添加内容的位置 内容位于标签中间  若是图标放在属性icon -->
            <el-button
              slot="append"
              icon="el-icon-search"
              @click="getUserList"
            ></el-button>
          </el-input>
        </el-col>
        <el-col :span="4">
          <!-- 绑定事件触发的一定是个函数  表达式也是函数  不能只是个变量 -->
          <el-button type="primary" @click="addDialogVisible = true"
            >添加用户</el-button
          >
        </el-col>
      </el-row>
      <!-- 用户列表区域 -->
      <!-- data是数据源 prop接收源对象中的属性名   -->
      <!-- table组件中的竖行会根据数量自适应  不传prop显示空白 -->
      <el-table :data="userlist" border stripe>
        <!-- type=index在前面添加一个索引列 -->
        <el-table-column type="index"></el-table-column>
        <el-table-column label="姓名" prop="username"></el-table-column>
        <el-table-column label="邮箱" prop="email"></el-table-column>
        <el-table-column label="电话" prop="mobile"></el-table-column>
        <el-table-column label="角色" prop="role_name"></el-table-column>
        <el-table-column label="状态" prop="mg_state">
          <!-- scope在2.6版本已经废弃了 这里的elementUI是旧的基于2.x版本的 -->
          <!-- slot-scope接收另一个组件数据总对象 -->
          <!-- slot插槽会覆盖prop  有slot prop就失效了 -->
          <template slot-scope="scope">
            <!-- scope.row拿到另一个组件的此行数据的对象 -->
            <!-- {{ scope.row }} -->
            <!-- 在solt插槽里的内部子组件可以直接使用接受过来的数据 -->
            <!-- el-table-column中的内容会在table表格的每列的所有行都生效 -->
            <el-switch v-model="scope.row.mg_state"> </el-switch>
          </template>
        </el-table-column>
        <!-- elementUI的组件可以用普通css修饰 -->
        <el-table-column label="操作" width="180px">
          <template slot-scope="scope">
            <!-- 蓝色按钮 -->

            <el-button
              type="primary"
              icon="el-icon-edit"
              size="mini"
              @click="showEditDialog(scope.row.id)"
            ></el-button>

            <!-- 红色按钮 -->
            <!-- scope是表格专有的变量 scope.row是当前行数据的对象 -->
            <el-button
              type="danger"
              icon="el-icon-delete"
              size="mini"
              @click="removeUserById(scope.row.id)"
            ></el-button>
            <!-- enterable解决鼠标位于弹出提示消息内容本身时候消息仍处于触发状态  应该是只在按钮位置时显示消息 而不会盖住其他按钮 -->
            <!-- 橙色按钮 -->
            <!-- 鼠标经过显示提示信息 -->
            <el-tooltip
              effect="dark"
              content="分配角色"
              placement="top"
              :enterable="false"
            >
              <el-button
                type="warning"
                icon="el-icon-setting"
                size="mini"
                @click="setRole(scope.row)"
              ></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页区域 -->
      <!-- 有的elementUI的组件也需要到数据控制层添加函数   有的是在data数据层添加数据 -->

      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="queryInfo.pagenum"
        :page-sizes="[1, 2, 5, 10]"
        :page-size="queryInfo.pagesize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      >
      </el-pagination>
    </el-card>
    <!-- 添加用户的对话框 -->
    <!-- 只有:绑定的属性页面会一直保持着和数据层的联系自动响应改变 -->
    <el-dialog
      title="提示"
      :visible.sync="addDialogVisible"
      width="50%"
      @close="addDialogClosed"
    >
      <!-- 内容主体区域 -->
      <!-- 带ref属性的把组件映射到了$ref全局变量中，在其他地方可以使用this.$ref.refname调用 -->
      <el-form
        :model="addForm"
        :rules="addFormRules"
        ref="addFormRef"
        label-width="70px"
      >
        <!-- 属性prop与数据层的rule验证规则相同的时候验证生效 -->
        <el-form-item label="用户名" prop="username">
          <el-input v-model="addForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="addForm.password"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="addForm.email"></el-input>
        </el-form-item>
        <el-form-item label="手机" prop="mobile">
          <el-input v-model="addForm.mobile"></el-input>
        </el-form-item>
      </el-form>
      <!-- 底部区域 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addUser">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 修改用户蓝色按钮弹出的对话框 -->
    <el-dialog
      title="修改用户"
      :visible.sync="editDialogVisible"
      width="50%"
      @close="editDialogClosed"
    >
      <el-form
        :model="editForm"
        :rules="editFormRules"
        ref="editFormRef"
        label-width="70px"
      >
        <el-form-item label="用户名">
          <el-input v-model="editForm.username" disabled></el-input>
        </el-form-item>

        <el-form-item label="邮箱" prop="email">
          <el-input v-model="editForm.email"></el-input>
        </el-form-item>

        <el-form-item label="手机" prop="mobile">
          <el-input v-model="editForm.mobile"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="editUserInfo">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 分配角色的对话框 -->
    <el-dialog
      title="分配角色"
      :visible.sync="setRoleDialogVisible"
      width="50%"
      @close="setRoleDialogClosed"
    >
      <div>
        <p>当前的用户:{{ userInfo.username }}</p>
        <p>当前的角色:{{ userInfo.rolename }}</p>
        <p>
          分配新角色:
          <el-select v-model="selectedRoleId" placeholder="请选择">
            <!-- :value是指下拉框选中项传递给后台的值  类似与input的value -->
            <!-- 下拉框的数据都是从roleList中取出的  :value的值会显示在对话框 -->
            <el-option
              v-for="item in rolesList"
              :key="item.id"
              :label="item.roleName"
              :value="item.id"
            >
            </el-option>
          </el-select>
        </p>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="setRoleDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveRoleInfo"
          >确 定</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    //自定义验证规则就是封装一个正则组成的函数  向外暴露需要验证信息参数
    //正则相当于加了给value加了个过滤器  不通过报错 通过没效果
    //cb回调函数退出验证
    var checkEmail = (rule, value, cb) => {
      //正则必须在一行  换行要加换行符\r或\n
      const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
      //.test是正则对象的方法
      if (regEmail.test(value)) {
        //符合规则时候
        return cb();
      }
      //不符合规则时候

      cb(new Error("请输入合法的邮箱"));
    };
    //结尾不能加逗号
    var checkMobile = (rule, value, cb) => {
      //验证手机号的规则
      const regMobile =
        /^(0|86|17951)?(13[0-9]|15[0123456789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;

      if (regMobile.test(value)) {
        return cb();
      }
      cb(new Error("请输入合法的手机号"));
    };
    //自定义的规则放上面 自定义函数放methods    对象数组普通变量放data里  data的必须有冒号
    return {
      queryInfo: {
        query: "",
        pagenum: 1,
        pagesize: 2,
      },
      // 组件中的变量不能凭空出现 可以是经过data层中的数据如for遍历数组而来
      userlist: [],
      total: 0,
      // 控制添加用户按钮的触发对话框的显示与隐藏
      addDialogVisible: false,
      // 添加用户按钮触发对话框里用户表达数据的内容
      addForm: {
        username: "",
        password: "",
        email: "",
        mobile: "",
      },
      //添加用户按钮触发对话框的验证规则对象
      addFormRules: {
        username: [
          //规定为必填项若没有填触发第一条验证
          { required: true, message: "输入名为必填项", trigger: "blur" },
          //填写不符合触发第二条验证
          {
            min: 3,
            max: 10,
            message: "用户名长度为3~10个字符之间",
            trigger: "blur",
          },
        ],
        password: [
          { required: true, message: "密码为必填项", trigger: "blur" },
          { min: 6, max: 15, message: "密码为6~15个字符之间", trigger: "blur" },
        ],
        email: [
          { required: true, message: "邮箱为必填项", trigger: "blur" },
          //validator添加自定义规则
          { validator: checkEmail, trigger: "blur" },
        ],
        mobile: [
          { required: true, message: "手机号为必填项", trigger: "blur" },
          { validator: checkMobile, trigger: "blur" },
        ],
      },
      //控制修改用户对话框的显示与隐藏
      editDialogVisible: false,
      //蓝色按钮触发的用户信息对象
      editForm: {},
      //修改表单的验证规则对象
      editFormRules: {
        // validator自定义规则一次定义可多次使用
        email: [
          { required: true, message: "请输入用户邮箱", trigger: "blur" },
          { validator: checkEmail, trigger: "blur" },
        ],
        mobile: [
          { required: true, message: "请输入用户手机", trigger: "blur" },
          { validator: checkMobile, trigger: "blur" },
        ],
      },
      //控制分配角色对话框的显示与隐藏
      setRoleDialogVisible: false,
      //需要被分配角色的用户信息  点击事件触发函数携带的本行数据   放data做为中转
      userInfo: {},
      //所有角色的数据列表
      rolesList: [],
      //el-seleted下拉框选中的角色id的值
      selectedRoleId: '',
    };
  },
  created() {
    this.getUserList();
  },
  methods: {
    async getUserList() {
      const { data: res } = await this.$http.get("users", {
        params: this.queryInfo,
      });
      if (res.meta.status !== 200) {
        return this.$message.error("获取用户列表失败!");
      }
      this.userlist = res.data.users;
      this.total = res.data.total;
      console.log(res);
    },
    //监听添加用户对话框的关闭事件
    //关闭事件绑定在消息框  而触发重置的是消息框中的表单
    addDialogClosed() {
      this.$refs.addFormRef.resetFields();
    },
    //点击按钮 添加新用户
    addUser() {
      this.$refs.addFormRef.validate(async (valid) => {
        if (!valid) return;
        //users接口只要向它发送一个用户对象就能自动完成后台数据库添加
        const { data: res } = await this.$http.post("users", this.addForm);
        if (res.meta.status !== 201) {
          return this.$message.error("用户添加失败了~");
        }
        // 隐藏添加用户的对话框
        this.addDialogVisible = false;
        // 添加成后重新获取用户数据,不需要用户手动刷新
        this.getUserList();
        return this.$message.success("用户添加成功了~");
      });
    },
    //点击蓝色编辑按钮触发一个可编辑并提交就可以修改后台users表格的事件
    //第一步保存点击的蓝色按钮所在行的row.id  第二步根据id查询接口找到此行的对象
    //第三步 将找到的对象给触发的窗口中的表单

    async showEditDialog(id) {
      // console.log(id)  user/是后台给的接口
      const { data: res } = await this.$http.get("users/" + id);

      if (res.meta.status !== 200) {
        return this.$message.error("查询用户信息失败");
      }

      this.editForm = res.data;
      this.editDialogVisible = true;
    },
    //蓝色修改用户按钮触发的对话框关闭触发
    editDialogClosed() {
      this.$refs.editFormRef.resetFields();
    },
    //监听pagesize改变的事件
    // newSize newPage是在ele分页组件pageinnation中暴露的变量
    handleSizeChange(newSize) {
      this.queryInfo.pagesize = newSize;
      this.getUserList();
    },
    //监听页码值改变的事件
    handleCurrentChange(newPage) {
      this.queryInfo.pagenum = newPage;
      this.getUserList();
    },
    //修改用户信息并提交
    //关闭触发对整个表单进行验证  rule验证决定是否显示红色提示框
    //此处的全局验证能添加验证报错机制   验证通过后就成了一个触发事件 可以添加多个动作
    editUserInfo() {
      this.$refs.editFormRef.validate(async (valid) => {
        if (!valid) return;
        //修改用户信息后端设置为put 'users/'  参数id为必须 email mobile为可选
        //email mobile为需要修改成的新的数据  没有则表示不修改
        const { data: res } = await this.$http.put(
          "users/" + this.editForm.id,
          { email: this.editForm.email, mobile: this.editForm.mobile }
        );

        if (res.meta.status !== 200) {
          return this.$message.error("更新用户信息失败!");
        }
        //关闭蓝色按钮窗口
        this.editDialogVisible = false;
        //刷新数据列表
        this.getUserList();
        this.$message.success("更新用户信息成功!");
      });
    },
    //根据id删除对应的用户信息
    async removeUserById(id) {
      //弹窗询问用户是否删除数据
      //不加catch点击取消报错   catch中的return err将错误信息弹出返回给了confirmResult
      const confirmResult = await this.$confirm(
        "此操作将永久删除该用户, 是否继续?",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      ).catch((err) => err);
      // console.log(confirmResult);
      //点击确定控制台输出文本confirm  点击取消输出文本cancel
      //只有点击确定才是删除  点击取消或者其他地方关闭窗口都是取消删除  用!===  而不是"cancel"
      if (confirmResult !== "confirm") {
        return this.$message.info("已取消删除");
      }
      //使用接收到的 参数id
      //删除数据库中的单条信息 发送delete请求 携带'users/'和id 后端会删除数据库中对应信息
      const { data: res } = await this.$http.delete("users/" + id);

      if (res.meta.status !== 200) {
        return this.$message.error("删除用户失败！");
      }
      this.$message.success("删除用户成功!");
      this.getUserList();
    },
    //展示分配角色对话框
    async setRole(userInfo) {
      this.userInfo = userInfo;
      //在展示对话框之前，获取所有角色的列表
      const { data: res } = await this.$http.get("roles");
      if (res.meta.status !== 200) {
        return this.$message.error("获取角色列表失败！");
      }

      this.rolesList = res.data;
      this.setRoleDialogVisible = true;
    },
    //点击按钮  分配角色
    async saveRoleInfo() {
      if (!this.selectedRoleId) {
        return this.$message.error('请选择要分配的角色!')
      }

      const { data: res } = await this.$http.put(`users/${this.userInfo.id}/role`,
        {
          rid: this.selectedRoleId,
        }
      );

      if (res.meta.status !== 200) {
        return this.$message.error("更新角色失败！");
      }

      this.$message.success("更新角色成功！");
      this.getUserList();
      this.setRoleDialogVisible = false;
    },
    //分配角色对话框关闭时 清空重置seleted选中的效果  selectedRoleId为选中的多选项
    //selectedRoleId正在修改的表格的本行  下次可以设置任意行
    setRoleDialogClosed(){
      this.selectedRoleId=''
      this.userInfo=''
    }
  },
};
</script>

<style scoped>
</style>
